﻿// (c)2010 David Schwarz (david.schwarz@live.com)
// This file is licensed under GNU GPL v2 license, see more at http://www.gnu.org/licenses/gpl-2.0.html
namespace Z2.Core
{

	#region Using

	using System;
	using Microsoft.Xna.Framework;
	using System.Diagnostics;
	using System.Collections.Generic;

	#endregion

	/// <summary>
	/// Třída definující standrdní chování objektu (působící gravitace)
	/// </summary>
	internal class GravityBehavior : ObjectBehaviorBase
	{

		#region Const

		private const float GRAVITY_MAX = 10.0f;
		private const float GRAVITY_DEFAULT = 0.1f;
		private const float GRAVITY_BOOST = 0.5f;

		#endregion

		#region Constructor

		/// <summary>
		/// Konstruktor
		/// </summary>
		public GravityBehavior()
			: base()
		{
		}

		#endregion

		#region Override Methods

		/// <summary>
		/// Metoda, která modifikuje vektor pohybu objektu <paramref name="obj"/>
		/// </summary>
		/// <param name="obj"><see cref="ObjectBase"/></param>
		internal override void ModifyVector(ObjectBase obj)
		{
			if (obj.Sector == null)
			{
				Debug.WriteLine("obj.Sector == null");
				return;
			}
			List<ObjectBase> objects = World.Current.GetSectorsObjects(obj);
			
			bool collisionWithObject = false;

			// Změna vektoru v ose X
			if (obj.Change.X != 0)
			{
				obj.Move = new Vector2(obj.Move.X + obj.Change.X, obj.Move.Y);
				
				// Ošetření maximální rychlosti v ose X
				if (obj.MaxHorizontalSpeed > 0 && Math.Abs(obj.Move.X) > obj.MaxHorizontalSpeed)
				{
					obj.Move = new Vector2(obj.Move.X > 0 ? obj.MaxHorizontalSpeed : -obj.MaxHorizontalSpeed, obj.Move.Y);
				}
			}

			Rectangle rect = obj.GetRectangle(0, (WorldField.SIZE / 3));
			IntersectionResult result = World.Current.Intersects(obj, rect);

			// Musíme otestovat, zda je možné aby objekt někam "spadl"
			if (!result.IsCollision) // Pokud se pod objektem nic nenachází, můžeme na něj nechat působit gravitaci :))
			{
				// Ještě musíme otestovat, zda se pod ním nenachází nějaký jiný objekt
				foreach (ObjectBase objBase in objects)
				{
					if (objBase == obj)
					{
						continue;
					}
					result = obj.Intersects(objBase, rect);
					if (result.IsCollision)
					{
						obj.Move = new Vector2(
							obj.Move.X,
							obj.Move.Y + (result.Rectangle.Top - (obj.Position.Y + obj.Sprite.FrameHeight)));
						collisionWithObject = true;
						if (result.With != null && result.With.Type == ObjectType.Bendable)
						{
							result.With.ChangeVertical(2);
						}
					}
				}
				// Nenachází :)
				if (!collisionWithObject)
				{
					obj.Move = new Vector2(obj.Move.X, obj.Move.Y + GravityBehavior.GRAVITY_BOOST);
				}
			}

			collisionWithObject = false;

			if (obj.Move.X != 0) // Pokud se objekt hýbe v ose X
			{
				// Otestujeme kolizi se světem
				rect = obj.GetRectangle(obj.Move.X, 0);
				result = World.Current.Intersects(obj, rect);
				if (result.IsCollision && !obj.CheckFalseCollision(result))
				{
					obj.OnHorizontalCollision(result);
				}
				else
				{
					foreach (ObjectBase objBase in objects)
					{
						if (objBase == obj)
						{
							continue;
						}

						result = obj.Intersects(objBase, rect);
						if (result.IsCollision)
						{
							collisionWithObject = true;
							objBase.ChangeHorizontal(obj.Move.X);
							//if (result.With != null && result.With.Type == ObjectType.Bendable)
							//{
							//    result.With.ChangeVertical(2);
							//    collisionWithObject = false;
							//    continue;
							//}
							if (!obj.CheckFalseCollision(result))
							{
								obj.OnHorizontalCollision(result);
							}
							else
							{
								collisionWithObject = false;
							}

						}
					}

					if (!collisionWithObject)
					{
						// Může
						obj.Position = new Vector2(obj.Position.X + obj.Move.X, obj.Position.Y);
					}
				}
			}

			collisionWithObject = false;

			// Totéž pro osu Y
			if (Convert.ToInt32(obj.Move.Y) == 0)
			{
				return;
			}

			rect = obj.GetRectangle(0, obj.Move.Y);
			result = World.Current.Intersects(obj, rect);
			if (result.IsCollision)
			{
				obj.OnVerticalCollision(result);
				return;
			}

			rect = obj.GetRectangle(0, obj.Move.Y);
			foreach (ObjectBase objBase in objects)
			{
				if (objBase == obj) // Objekt nemůže kolidovat sám se sebou
				{
					continue;
				}
				result = obj.Intersects(objBase, rect);
				if (result.IsCollision)
				{
					collisionWithObject = true;
					//objBase.ChangeVertical(this.m_move.Y);
					//objBase.ChangeHorizontal(this.m_move.X);
					obj.OnVerticalCollision(result);
				}
			}

			if (!collisionWithObject)
			{
				if (obj.VerticalState == ObjectStateVertical.Idle)
				{
					obj.OnStartMovingVertical();
				}
				obj.VerticalState = obj.Move.Y > 0 ? ObjectStateVertical.Falling : ObjectStateVertical.Rising;
				obj.Position = new Vector2(obj.Position.X, obj.Position.Y + obj.Move.Y);
			}

		}

		#endregion

	}
}
